package com.keyidea.jfxui.core.system;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.keyidea.jfxui.core.constant.UserConstants;
import com.keyidea.jfxui.core.page.TableDataInfo;
import com.keyidea.jfxui.core.system.domain.AjaxResult;
import com.keyidea.jfxui.core.system.sqlite.entity.*;
import com.keyidea.jfxui.core.system.sqlite.mapper.*;
import com.keyidea.jfxui.core.system.vo.TreeSelect;
import com.keyidea.jfxui.core.util.StringUtils;
import feign.Param;
import feign.QueryMap;
import feign.RequestLine;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 角色 信息操作处理
 */
@Service
@RequiredArgsConstructor
public class SysRoleService extends BaseService {

    private final SysRoleMapper sysRoleMapper;

    private final SysRoleMenuMapper sysRoleMenuMapper;

    private final SysRoleDeptMapper sysRoleDeptMapper;

    private final SysUserRoleMapper sysUserRoleMapper;

    private final SysUserMapper sysUserMapper;

    private final SysDeptMapper sysDeptMapper;

    public TableDataInfo list(@QueryMap Map<String, Object> query) {
        SysRole param = BeanUtil.toBean(query, SysRole.class);
        List<SysRole> list = sysRoleMapper.selectRoleList(param);
        return getDataTable(list);
    }

    public void export(SysRole role) {
        List<SysRole> list = sysRoleMapper.selectRoleList(role);
//        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
//        util.exportExcel(response, list, "角色数据");
    }

    /**
     * 根据角色编号获取详细信息
     */
    public AjaxResult getInfo(@Param("roleId") Long roleId) {
        checkRoleDataScope(roleId);
        return success(sysRoleMapper.selectRoleById(roleId));
    }

    /**
     * 新增角色
     */
    public AjaxResult add(SysRole role) {
        if (!checkRoleNameUnique(role)) {
            return error("新增角色'" + role.getRoleName() + "'失败，角色名称已存在");
        } else if (!checkRoleKeyUnique(role)) {
            return error("新增角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }
        role.setCreateBy(getUsername());
        return toAjax(sysRoleMapper.insertRole(role));
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    public boolean checkRoleNameUnique(SysRole role) {
        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = sysRoleMapper.checkRoleNameUnique(role.getRoleName());
        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    public boolean checkRoleKeyUnique(SysRole role) {
        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = sysRoleMapper.checkRoleKeyUnique(role.getRoleKey());
        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 修改保存角色
     */
    public AjaxResult edit(SysRole role) {
        checkRoleAllowed(role);
        checkRoleDataScope(role.getRoleId());
        if (!checkRoleNameUnique(role)) {
            return error("修改角色'" + role.getRoleName() + "'失败，角色名称已存在");
        } else if (!checkRoleKeyUnique(role)) {
            return error("修改角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }
        role.setUpdateBy(getUsername());

        if (updateRole(role) > 0) {
            // 更新缓存用户权限
//            LoginUser loginUser = getLoginUser();
//            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
//            {
//                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
//                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
//                tokenService.setLoginUser(loginUser);
//            }
            return success();
        }
        return error("修改角色'" + role.getRoleName() + "'失败，请联系管理员");
    }

    public void checkRoleAllowed(SysRole role) {
        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) {
            error("不允许操作超级管理员角色");
        }
    }

    public int updateRole(SysRole role) {
        // 修改角色信息
        sysRoleMapper.updateRole(role);
        // 删除角色与菜单关联
        sysRoleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId());
        return insertRoleMenu(role);
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public int insertRoleMenu(SysRole role) {
        int rows = 1;
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<>();
        for (Long menuId : role.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(role.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
            rows = sysRoleMenuMapper.batchRoleMenu(list);
        }
        return rows;
    }

    /**
     * 修改保存数据权限
     */
    public AjaxResult dataScope(SysRole role) {
        checkRoleAllowed(role);
        checkRoleDataScope(role.getRoleId());
        return toAjax(authDataScope(role));
    }

    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    public int authDataScope(SysRole role) {
        // 修改角色信息
        sysRoleMapper.updateRole(role);
        // 删除角色与部门关联
        sysRoleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId());
        // 新增角色和部门信息（数据权限）
        return insertRoleDept(role);
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param role 角色对象
     */
    public int insertRoleDept(SysRole role) {
        int rows = 1;
        // 新增角色与部门（数据权限）管理
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        for (Long deptId : role.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(role.getRoleId());
            rd.setDeptId(deptId);
            list.add(rd);
        }
        if (!list.isEmpty()) {
            rows = sysRoleDeptMapper.batchRoleDept(list);
        }
        return rows;
    }

    /**
     * 状态修改
     */
    public AjaxResult changeStatus(SysRole role) {
        checkRoleAllowed(role);
        checkRoleDataScope(role.getRoleId());
        role.setUpdateBy(getUsername());
        return toAjax(sysRoleMapper.updateRole(role));
    }

    /**
     * 删除角色
     */
    public AjaxResult remove(@Param("roleIds") String roleIdsStr) {
        Long[] roleIds = Convert.convert(Long[].class, StrUtil.splitTrim(roleIdsStr, ","));
        for (Long roleId : roleIds) {
            checkRoleAllowed(new SysRole(roleId));
            checkRoleDataScope(roleId);
            SysRole role = sysRoleMapper.selectRoleById(roleId);
            if (sysUserRoleMapper.countUserRoleByRoleId(roleId) > 0) {
                return error(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        sysRoleMenuMapper.deleteRoleMenu(roleIds);
        // 删除角色与部门关联
        sysRoleDeptMapper.deleteRoleDept(roleIds);
        return toAjax(sysRoleMapper.deleteRoleByIds(roleIds));
    }

    /**
     * 获取角色选择框列表
     */
    public AjaxResult optionselect() {
        return success(sysRoleMapper.selectRoleList(new SysRole()));
    }

    /**
     * 查询已分配用户角色列表
     */
    public TableDataInfo allocatedList(@QueryMap Map<String, Object> query) {
        startPage(query);
        SysUser param = BeanUtil.toBean(query, SysUser.class);
        List<SysUser> list = sysUserMapper.selectAllocatedList(param);
        return getDataTable(list);
    }

    /**
     * 查询未分配用户角色列表
     */
    public TableDataInfo unallocatedList(@QueryMap Map<String, Object> query) {
        startPage(query);
        SysUser param = BeanUtil.toBean(query, SysUser.class);
        List<SysUser> list = sysUserMapper.selectUnallocatedList(param);
        return getDataTable(list);
    }

    /**
     * 取消授权用户
     */
    public AjaxResult cancelAuthUser(SysUserRole userRole) {
        return toAjax(sysUserRoleMapper.deleteUserRoleInfo(userRole));
    }

    /**
     * 批量取消授权用户
     */
    public AjaxResult cancelAuthUserAll(@QueryMap Map<String, Object> query) {
        Long roleId = (Long) query.get("roleId");
        Long[] userIds = Convert.convert(Long[].class, query.get("userIds"));
        return toAjax(sysUserRoleMapper.deleteUserRoleInfos(roleId, userIds));
    }

    /**
     * 批量选择用户授权
     */
    public AjaxResult selectAuthUserAll(@QueryMap Map<String, Object> query) {
        Long roleId = (Long) query.get("roleId");
        Long[] userIds = Convert.convert(Long[].class, query.get("userIds"));
        checkRoleDataScope(roleId);
        return toAjax(insertAuthUsers(roleId, userIds));
    }

    /**
     * 批量选择授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要授权的用户数据ID
     * @return 结果
     */
    public int insertAuthUsers(Long roleId, Long[] userIds) {
        // 新增用户与角色管理
        List<SysUserRole> list = new ArrayList<SysUserRole>();
        for (Long userId : userIds) {
            SysUserRole ur = new SysUserRole();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        return sysUserRoleMapper.batchUserRole(list);
    }

    /**
     * 获取对应角色部门树列表
     */
    public AjaxResult deptTree(@Param("roleId") Long roleId) {
        AjaxResult ajax = AjaxResult.success();

        SysRole role = sysRoleMapper.selectRoleById(roleId);
        List<Long> longs = sysDeptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());

        ajax.put("checkedKeys", longs);
        ajax.put("depts", buildDeptTreeSelect(sysDeptMapper.selectDeptList(new SysDept())));
        return ajax;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param depts 部门列表
     * @return 下拉树结构列表
     */
    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
        List<SysDept> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 构建前端所需要树结构
     *
     * @param depts 部门列表
     * @return 树结构列表
     */
    public List<SysDept> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<SysDept>();
        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t) {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tlist = new ArrayList<SysDept>();
        Iterator<SysDept> it = list.iterator();
        while (it.hasNext()) {
            SysDept n = (SysDept) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDept> list, SysDept t) {
        return getChildList(list, t).size() > 0;
    }

    /**
     * 校验角色是否有数据权限
     *
     * @param roleIds 角色id
     */
    public void checkRoleDataScope(Long... roleIds) {
//        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
//        {
//            for (Long roleId : roleIds)
//            {
//                SysRole role = new SysRole();
//                role.setRoleId(roleId);
//                List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
//                if (StringUtils.isEmpty(roles))
//                {
//                    throw new ServiceException("没有权限访问角色数据！");
//                }
//            }
//        }
    }
}
